/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 沈明月
 * Date: 2022-11-30
 * Time: 12:25
 */


//方法内部不能定义由static修饰的变量
//静态成员变量在方法区存放


//继承

//下面的Dog和Cat类它们在许多地方都有相似之处，于是不免觉得重复写很是麻烦，于是如何才能把它们相同的地方抽出来放一起呢？
//答案是通过继承

/*class Dog{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+" 正在吃饭！");
    }
    public void wangWang(){
        System.out.println(name+" 正在旺旺叫！");
    }
}

class Cat{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+" 正在吃饭！");
    }
    public void miaoMiao(){
        System.out.println(name+" 正在喵喵叫！");
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "小白";
        dog.eat();//小白 正在吃饭！
        dog.wangWang();//小白 正在旺旺叫！

        Cat cat = new Cat();
        cat.name = "小黑";
        cat.eat();//小黑 正在吃饭！
        cat.miaoMiao();//小黑 正在喵喵叫！
    }
}*/



//继承最大的意义就是对代码进行复用
//继承主要解决的问题就是：共性的抽取，实现代码的复用
//子类继承父类以后，必须（不会在语法上给你报错，只是逻辑上，通俗来说就是按理说，按道理）要新添自己特有的成员，体现出与基类的不同，否则就没有继承的必要了
//子类会把父类里面的成员变量和成员方法继承到子类中
//只能继承一个类，不能继承多个类

//改写后：


/*
class Animals{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+" 正在吃饭！");
    }
}

class Dog extends Animals {
    public void wangWang(){
        System.out.println(name+" 正在汪汪叫！");
    }
}

class Cat extends Animals {
    public void miaoMiao(){
        System.out.println(name+" 正在喵喵叫！");
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "小白";
        dog.wangWang();//小白 正在汪汪叫！

        Cat cat = new Cat();
        cat.name = "小黑";
        cat.miaoMiao();//小黑 正在喵喵叫！
    }
}
*/






/*
class Base{
    public int a = 20;
    public int b = 2;
    public int c = 199;

    public void methodBase(){
        System.out.println("Base");
    }
}

class Derived extends Base {
    public int d = 10;//和父类里面的成员变量的名字都不一样

    public void methodDerived(){//和父类里面的成员方法的名字都不一样
        System.out.println("Derived");
    }

    //可以在子类里面调用父类的方法：
    public void func1(){
        methodBase();
        methodDerived();
    }

    public void func(){
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
        derived.func1();
    }
}
*/





/*class Base{
    public int a;
    public int b;
    public int c = 199;

    public void methodBase(){
        System.out.println("Base");
    }
}

class Derived extends Base {
    //子类有就拿子类的，子类没有再拿父类的
    //如果父类和子类有同名的成员变量，优先使用子类自己的（就近原则）
    public int c = 9;

    public void methodBase(){
        System.out.println("Derived");
    }

    public void func1(){
        methodBase();
        methodBase();
    }

    public void func(){
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(super.c);
        //通过关键字super可以访问到当前类的父类的成员变量
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
        derived.func1();//这里调用的都是子类里面的方法，即打印Derived两次，也遵循就近原则
        //要想通过methodBase()方法访问到父类里面的那个methodBase()则要通过super
        //即super.methodBase()
    }
}*/


//super：只是一个关键字，最大的作用就是在读写代码的时候体现出更好的可读性，只能在非静态代码块里使用

//super用法：
//super.date：在子类中访问父类的成员变量
//super.func()：在子类中访问父类的成员方法


//重载（overloading）：方法名相同，参数列表不同

/*
class Animals{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+" 正在吃饭！");
    }

    //构造方法：
    public Animals(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Dog extends Animals {
//构造方法：
*/
/*    public Dog(){
        super("小一",10);
    }*//*


//也可以写作：
    public Dog(String name, int age) {
        super(name, age);
    }

    public void wangWang(){
        System.out.println(name+" 正在旺旺叫！");
    }
}

class Cat extends Animals {

    public int size;

    //构造方法：
*/
/*    public Dog(){
        super("小一",10);
    }*//*

//也可以写作：

    public Cat(String name, int age,int size) {
        super(name, age);
        this.size = size;
        //注意这里的size的构造一定要在父类的构造结束以后才能构造，否则会报错。
        //super在子类构造方法内调用父类构造方法的时候一定要放在第一行

        //同样，this引用在构造方法里使用的时候也是要放在第一行的，所以，this和super不能同时出现在在同一个构造方法中

    }

    public void miaoMiao(){
        System.out.println(name+" 正在喵喵叫！");
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Dog dog = new Dog("小白",12);
        dog.wangWang();//小白 正在旺旺叫！

        Cat cat = new Cat("小黑",19,29);
        cat.miaoMiao();//小黑 正在喵喵叫！
    }
}
*/




/*class Animals{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+" 正在吃饭！");
    }
    //如果父类和子类中没有构造方法，编译器会帮你在父类中加一个无参的构造方法：
    public Animals(){

    }

}

class Dog extends Animals {
    //如果父类和子类中没有构造方法，编译器会帮你在子类中加一个无参的构造方法：
    public Dog(){
        super();//super只能能在子类的构造方法内部使用
    }

    public void wangWang(){
        System.out.println(name+" 正在旺旺叫！");
    }
}

class Cat extends Animals {

    public int size;

    //如果父类和子类中没有构造方法，编译器会帮你在子类中加一个无参的构造方法：
    public Cat(){
        super();
    }
    public void miaoMiao(){
        System.out.println(name+" 正在喵喵叫！");
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.wangWang();

        Cat cat = new Cat();
        cat.miaoMiao();
    }
}*/



//super和this的异同点：

//相同点：
//都是Java中的关键字
//只能在类的非静态方法中使用，用来访问非静态成员的方法和字段
//在构造方法中调用的时候，都必须是方法中的第一条语句，且不能同时存在

//不同点：
//this是当前对象的引用，当前对象即调用实例方法的对象，super相当于是子类对象中从父类继承下来部分成员的引用
//在非静态成员方法中，this用来访问本类的方法和属性，super用来访问父类继承下来的方法和属性
//在构造方法中，this()用于调用本类构造方法，super()用于调用父类的构造方法，两种调用不能同时在构造方法中使用
//构造方法中一定会存在super()的调用，用户没有写，编译器也会增加，但是this()用户如果不写的话就没有




/*
class Animals{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name+" 正在吃饭！");
    }

    static {
        System.out.println("Animals static{}");
    }
    {
        System.out.println("Animals {}");
    }

    //如果父类和子类中没有构造方法，编译器会帮你在父类中加一个无参的构造方法：
    public Animals(){
        System.out.println("Animals()");
    }

    public Animals(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("带有两个参数的构造方法！");
    }
}

class Dog extends Animals {

    static {
        System.out.println("Dog static{}");
    }
    {
        System.out.println("Dog {}");
    }
    public Dog(){
        System.out.println("DOG()");
    }
    public Dog(String name, int age) {
        //super("小白",1);
        System.out.println("带有两个参数的构造方法！");
    }

    public void wangWang(){
        System.out.println(name+" 正在旺旺叫！");
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println("==============");
        Dog dog1 = new Dog();
        //执行顺序：
        //父类静态代码块-->子类静态代码块-->父类构造代码块-->子类构造代码块
        //父类的静态-->子类的静态-->父类的实例-->父类的构造方法-->子类的实例-->子类的构造方法
        //静态代码块只执行一次
        //父类优先子类执行，静态代码块优先非静态代码块
    }
}*/

/*class Animals{
    public String name;
    public int age;

    static {
        System.out.println("父类静态代码块");
    }
    {
        System.out.println("父类实例代码块");
    }

    //如果父类和子类中没有构造方法，编译器会帮你在父类中加一个无参的构造方法：
    public Animals(){
        System.out.println("父类构造方法");
    }
}

class Dog extends Animals {

    static {
        System.out.println("子类静态代码块");
    }
    {
        System.out.println("子类实例代码块");
    }
    public Dog(){
        System.out.println("子类构造方法");
    }
}

public class KnowledgeOne {
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println("==============");
        Dog dog1 = new Dog();
    }
}*/




//被private修饰的可以被继承，但是不能访问（因为不是在同一个类里面了）


//继承的分类：
//单继承：爸爸和儿子
//多层继承：孙子、爸爸、爷爷
//不同类型继承同一个类：爸爸、儿子1、儿子2
//多继承：一个儿子有好几个爹，Java中不支持，会报错
//当一个类不想被继承的时候，加一个final即可（final class Animals）
//不能被继承的类叫做密封类


//举例：
//final int A = 10;A要大写，A的值不可以修改，变成了一个常量（类似于const）
//如果是成员变量被final修饰，定义的同时要加初始值

/*public class KnowledgeOne {
    public static void main(String[] args) {
        final int[] arr = {1,2,3,4};

        arr = new int[10];//error
        arr[0] = 19;//right
//        上面两行代码中,第一行是错的，第二行是对的
//        原因：
//        arr被final修饰，表明arr里面的内容不能改变，而arr里存放的是数组的地址（换而言之，arr指向的对象不能改变）
//        第一行表明重新new了一个数组，改变了arr指向的对象,显然违背了final的使用，错误
//        第二含虽然改变了数组里面第一个元素的值，但是它只是改变了指向的对象的内容，并没有改变指向的对象，所以是ok的
    }
}*/



//组合：是一种代码的实现方式。在一个类里面，将其他类作为这个类的成员使用

/*
class Teacher{

}

class Student{

}

class School{
    public Teacher[] teachers = new Teacher[3];//类类型
    public Student[] students = new Student[3];
}
*/
